package com.jrauto.CarAppBackend.service.impl;

/**
 * @author : huiMing
 * Date : 2025年09月12日 10:45
 * @version V1.0
 */

import com.alibaba.fastjson.JSON;
import com.jrauto.CarAppBackend.entity.Message;
import com.jrauto.CarAppBackend.entity.dto.MessageDTO;
import com.jrauto.CarAppBackend.entity.dto.WebSocketMessageDTO;
import com.jrauto.CarAppBackend.service.MessageService;
import com.jrauto.CarAppBackend.service.UserOnlineService;
import com.jrauto.CarAppBackend.service.WebSocketService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WebSocket服务实现类 - 优化版
 * 集成Redis在线状态管理，提升性能和可靠性
 */
/**
 * WebSocket服务实现类
 */
@Slf4j
@Service
public class WebSocketServiceImpl implements WebSocketService {

    @Resource
    private MessageService messageService;

    @Resource
    private UserOnlineService userOnlineService;

    // 存储用户WebSocket连接
    private final Map<String, WebSocketSession> userSessions = new ConcurrentHashMap<>();

    @Override
    public void userOnline(Integer userId, WebSocketSession session) {
        try {
            // 1. 存储WebSocket连接
            userSessions.put(userId.toString(), session);

            // 2. 获取用户IP地址
            String ipAddress = getClientIpAddress(session);

            // 3. 更新在线状态
            userOnlineService.userOnline(userId, ipAddress);

            // 4. 推送离线消息
            pushOfflineMessages(userId);

            log.info("用户 {} 建立WebSocket连接成功，IP: {}", userId, ipAddress);

        } catch (Exception e) {
            log.error("用户上线失败: userId={}, error={}", userId, e.getMessage(), e);
        }
    }

    @Override
    public void userOffline(Integer userId, String sessionId) {
        try {
            // 1. 移除WebSocket连接
            WebSocketSession session = userSessions.remove(userId.toString());

            // 2. 更新离线状态
            userOnlineService.userOffline(userId);

            // 3. 关闭WebSocket连接
            if (session != null && session.isOpen()) {
                session.close();
            }

            log.info("用户 {} 下线成功", userId);

        } catch (Exception e) {
            log.error("用户下线失败: userId={}, error={}", userId, e.getMessage(), e);
        }
    }

    @Override
    public boolean sendMessageToUser(Integer userId, WebSocketMessageDTO message) {
        try {
            WebSocketSession session = userSessions.get(userId.toString());

            if (session != null && session.isOpen()) {
                String messageJson = JSON.toJSONString(message);
                session.sendMessage(new TextMessage(messageJson));

                // 刷新用户在线状态
                userOnlineService.refreshUserOnlineStatus(userId);

                log.debug("发送消息给用户 {} 成功: {}", userId, message.getType());
                return true;
            } else {
                log.warn("用户 {} 的WebSocket连接不存在或已关闭", userId);
                // 清理无效连接
                userSessions.remove(userId.toString());
                return false;
            }

        } catch (Exception e) {
            log.error("发送消息给用户失败: userId={}, error={}", userId, e.getMessage(), e);
            return false;
        }
    }

    @Override
    public void broadcastToRoom(Integer roomId, WebSocketMessageDTO message) {
        try {
            // 获取房间内的用户列表
            List<Integer> roomUserIds = messageService.getRoomUserIds(roomId);

            for (Integer userId : roomUserIds) {
                sendMessageToUser(userId, message);
            }

            log.info("广播消息到房间 {} 成功，用户数: {}", roomId, roomUserIds.size());

        } catch (Exception e) {
            log.error("广播消息到房间失败: roomId={}, error={}", roomId, e.getMessage(), e);
        }
    }

    @Override
    public boolean isUserOnline(Integer userId) {
        // 优先检查本地连接
        boolean hasLocalConnection = userSessions.containsKey(userId.toString()) &&
                userSessions.get(userId.toString()).isOpen();

        if (!hasLocalConnection) {
            // 本地没有连接，检查Redis状态
            return userOnlineService.isUserOnline(userId);
        }

        return true;
    }

    @Override
    public WebSocketSession getUserSession(Integer userId) {
        return userSessions.get(userId.toString());
    }

    @Override
    public void pushOfflineMessages(Integer userId) {
        try {
            List<Message> offlineMessages = messageService.getOfflineMessages(userId);

            if (!offlineMessages.isEmpty()) {
                WebSocketMessageDTO pushMessage = new WebSocketMessageDTO();
                pushMessage.setType("OFFLINE_MESSAGES");
                pushMessage.setData(offlineMessages);

                sendMessageToUser(userId, pushMessage);

                // 标记消息为已读
                messageService.markMessagesAsRead(offlineMessages);

                log.info("推送离线消息给用户 {}: {} 条", userId, offlineMessages.size());
            }

        } catch (Exception e) {
            log.error("推送离线消息失败: userId={}, error={}", userId, e.getMessage(), e);
        }
    }

    @Override
    public void sendHeartbeat(WebSocketSession session) {
        try {
            WebSocketMessageDTO heartbeatMessage = new WebSocketMessageDTO();
            heartbeatMessage.setType("HEARTBEAT");
            heartbeatMessage.setTimestamp(System.currentTimeMillis());

            String messageJson = JSON.toJSONString(heartbeatMessage);
            session.sendMessage(new TextMessage(messageJson));

        } catch (Exception e) {
            log.error("发送心跳消息失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 处理WebSocket消息
     */
    public void handleMessage(String userId, WebSocketMessageDTO message) {
        try {
            Integer userIdInt = Integer.parseInt(userId);

            // 刷新用户在线状态
            userOnlineService.refreshUserOnlineStatus(userIdInt);

            switch (message.getType()) {
                case "CHAT":
                    handleChatMessage(userIdInt, message);
                    break;
                case "PING":
                    handlePingMessage(userIdInt);
                    break;
                case "TYPING":
                    handleTypingMessage(userIdInt, message);
                    break;
                default:
                    log.warn("未知的消息类型: {}", message.getType());
            }

        } catch (Exception e) {
            log.error("处理WebSocket消息失败: userId={}, messageType={}, error={}",
                    userId, message.getType(), e.getMessage(), e);
        }
    }

    /**
     * 处理聊天消息
     */
    private void handleChatMessage(Integer userId, WebSocketMessageDTO message) {
        try {
            // 保存消息到数据库
            MessageDTO savedMessage = messageService.sendMessage(
                    message.getRoomId(),
                    userId,
                    message.getReceiverId(),
                    message.getMessageType(),
                    message.getContent()
            );

            // 构造响应消息
            WebSocketMessageDTO responseMessage = new WebSocketMessageDTO();
            responseMessage.setType("MESSAGE");
            responseMessage.setData(savedMessage);

            // 发送给房间内的其他用户
            broadcastToRoom(message.getRoomId(), responseMessage);

        } catch (Exception e) {
            log.error("处理聊天消息失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 处理心跳消息
     */
    private void handlePingMessage(Integer userId) {
        try {
            WebSocketMessageDTO pongMessage = new WebSocketMessageDTO();
            pongMessage.setType("PONG");
            pongMessage.setTimestamp(System.currentTimeMillis());

            sendMessageToUser(userId, pongMessage);

        } catch (Exception e) {
            log.error("处理心跳消息失败: userId={}, error={}", userId, e.getMessage());
        }
    }

    /**
     * 处理输入状态消息
     */
    private void handleTypingMessage(Integer userId, WebSocketMessageDTO message) {
        try {
            // 转发输入状态给房间内其他用户
            broadcastToRoom(message.getRoomId(), message);

        } catch (Exception e) {
            log.error("处理输入状态消息失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(WebSocketSession session) {
        try {
            String remoteAddress = session.getRemoteAddress() != null ?
                    session.getRemoteAddress().getAddress().getHostAddress() : "unknown";

            // 检查是否有代理IP
            String xForwardedFor = (String) session.getAttributes().get("X-Forwarded-For");
            if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
                return xForwardedFor.split(",")[0].trim();
            }

            String xRealIp = (String) session.getAttributes().get("X-Real-IP");
            if (xRealIp != null && !xRealIp.isEmpty()) {
                return xRealIp;
            }

            return remoteAddress;

        } catch (Exception e) {
            log.debug("获取客户端IP失败: {}", e.getMessage());
            return "unknown";
        }
    }

    /**
     * 获取当前在线用户数量
     */
    public long getOnlineUserCount() {
        return userOnlineService.getOnlineUserCount();
    }

    /**
     * 清理无效连接
     */
    public void cleanInvalidSessions() {
        userSessions.entrySet().removeIf(entry -> {
            WebSocketSession session = entry.getValue();
            if (session == null || !session.isOpen()) {
                String userId = entry.getKey();
                userOnlineService.userOffline(Integer.parseInt(userId));
                log.info("清理无效WebSocket连接: userId={}", userId);
                return true;
            }
            return false;
        });
    }
}
